package com.jy.api.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jy.api.dao.*;
import com.jy.api.domain.*;
import com.jy.api.enums.OrderPayChannel;
import com.jy.api.payReq.*;
import com.jy.api.payRes.*;
import com.jy.api.service.StorePayService;
import com.jy.api.util.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
@Service
public class SaoBeiServiceImpl implements StorePayService {
    String base_url = "http://pay.lcsw.cn/lcsw";

    @Autowired
    private AliyunMNSSend aliyunMNSSend;
    @Autowired
    private OrderDao orderDao;
    @Autowired
    private PaymentDao paymentDao;
    @Autowired
    private TransactionTemplate transactoinTemplate;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RewardDao rewardDao;
    @Autowired
    private StoreDao storeDao;
    @Autowired
    private RedisSyncLocker redisSyncLocker;
    @Autowired
    private AccountBalanceDao accountBalanceDao;
    @Autowired
    private StorePayDao storePayDao;
    @Value("${api.gateway.url}")
    private String baseURL;
    @Autowired
    private PaymentServiceImpl service;


    public AllPayBaseResult finalSaoBeiPay(Order order, String authCode, StorePay storePay, Store store) throws Exception {
        AllPayBaseResult payResult = saoBeiPay(order, authCode, storePay);
        log.info("门店{}, 订单号{}, 操作{}, 支付返回结果{},订单内容{}", order.getStoreId(), order.getId(), "支付开始", payResult, order);
        log.info("payResult" + payResult);
        order.setPayChannel(OrderPayChannel.SAO_BEI);
        if (payResult.isSuccess()) {
            // 支付成功，更新订单状态
            Payment payment = service.createPaymentBySwiftPassResult(payResult, storePay.getStoreId());
            // TODO: 2018/8/23  订单状态不应该区分是否履行。该平台可以不管理订单履行情况，因为一般都是线下履行
            if (OrderSource.POS == order.getSource()) {
                order.setStatus(OrderStatus.FINISHED);
            } else {
                order.setStatus(OrderStatus.UNFINISHED);
            }
            order.setPaymentTime(payment.getCreateTime());
            order.setPayId(payment.getId());
            order.setChannel(payResult.getTradeType());
            log.info("门店{}, 订单号{}, 操作{}, 支付返回结果{}", order.getStoreId(), order.getId(), "支付成功", payResult);
            orderDao.save(order);
            paymentDao.save(payment);
            service.postPaymentSuccess(order, store);
        } else if (payResult.isFailed()) {
            // 支付失败，允许订单再次支付
            order.setStatus(OrderStatus.CANCELED);
            orderDao.save(order);
        } else {
            // 支付结果不确定
            order.setStatus(OrderStatus.NOTSURE);
            orderDao.save(order);
            log.info("门店{}, 订单号{}, 操作{}, 支付返回结果{}", order.getStoreId(), order.getId(), "支付结果不确定", payResult);
            aliyunMNSSend.sendClint(order.getId());
        }
        redisTemplate.opsForValue().set(order.getId(), order.getId(), 5, TimeUnit.SECONDS);
        return payResult;
    }


    public AllPayBaseResult saoBeiPay(Order order, String authCode, StorePay storePay) throws Exception {
        String prePay_url = base_url + "/pay/100/barcodepay";
        SaoBeiPayReq req = new SaoBeiPayReq(order, authCode);
        AllPayBaseResult baseResult = new AllPayBaseResult();
        SaoBeiPayRes posPrePayRe;
        req.setMerchant_no(storePay.getMchId());
        req.setTerminal_id(storePay.getTerminalId());
        req.setAuth_no(authCode);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        req.setTerminal_time(simpleDateFormat.format(order.getAddTime()));
        String parm = "pay_ver=" + req.getPay_ver() + "&pay_type=" + req.getPay_type() + "&service_id="
                + req.getService_id() + "&merchant_no=" + req.getMerchant_no() + "&terminal_id="
                + req.getTerminal_id() + "&terminal_trace=" + req.getTerminal_trace()
                + "&terminal_time=" + req.getTerminal_time() + "&auth_no=" + req.getAuth_no() + "&total_fee=" + req.getTotal_fee()
                + "&access_token=" + storePay.getAccessToken();
        String sign = sign(parm, "utf-8");
        System.out.println(parm);
        String xmlText = tojson(prePay_url, saoBeiSort(req, sign).toJSONString());
        posPrePayRe = JSON.parseObject(xmlText, SaoBeiPayRes.class);
        log.info("门店{}, 订单号{}, 操作{}, 操作内容{}", order.getStoreId(), order.getId(), "扫呗支付信息返回结果");
        if (posPrePayRe.getReturn_code().equals("01")) {
            switch (posPrePayRe.getResult_code()) {
                case "01":
                    baseResult.setStatus("0");
                    baseResult.setResultCode("0");
                    baseResult.setMchId(posPrePayRe.getMerchant_no());
                    baseResult.setOutTradeNo(posPrePayRe.getTerminal_trace());
                    baseResult.setTotalFee(Integer.valueOf(posPrePayRe.getTotal_fee()));
                    baseResult.setTimeEnd(posPrePayRe.getEnd_time());
                    baseResult.setErrMsg(posPrePayRe.getReturn_msg());
                    baseResult.setTradeType(dealPayType(posPrePayRe.getPay_type()));
                    break;
                case "02":
                    baseResult.setStatus("1");
                    baseResult.setResultCode("1");
                    baseResult.setNeedQuery("N");
                    break;
                case "03":
                    baseResult.setStatus("1");
                    baseResult.setResultCode("1");
                    baseResult.setNeedQuery("Y");
                    break;
            }
        } else {
            baseResult.setStatus("1");
            baseResult.setResultCode("1");
        }
        return baseResult;
    }


    public AllPayBaseQueryResult saoBeiPayQuery(String orderId, StorePay storePay) throws Exception {
        Order order = orderDao.findOne(orderId);
        String prePay_url = base_url + "/pay/100/query";
        SaoBeiQueryPayReq req = new SaoBeiQueryPayReq();
        AllPayBaseQueryResult baseResult = new AllPayBaseQueryResult();
        SaoBeiQueryPayRes posPrePayRe;
        req.setMerchant_no(storePay.getMchId());
        req.setTerminal_trace(order.getCode());
        req.setTerminal_id(storePay.getTerminalId());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        req.setPay_time(simpleDateFormat.format(order.getAddTime()));
        req.setTerminal_time(simpleDateFormat.format(new Date()));
        req.setPay_trace(orderId);
        req.setOut_trade_no("");
        String parm = "pay_ver=" + req.getPay_ver() + "&pay_type=" + req.getPay_type() + "&service_id="
                + req.getService_id() + "&merchant_no=" + req.getMerchant_no() + "&terminal_id="
                + req.getTerminal_id() + "&terminal_trace=" + req.getTerminal_trace()
                + "&terminal_time=" + req.getTerminal_time() + "&out_trade_no=" + ""
                + "&access_token=" + storePay.getAccessToken();
        String sign = sign(parm, "utf-8");
        String xmlText = tojson(prePay_url, saoBeiSort(req, sign).toJSONString());
        posPrePayRe = JSON.parseObject(xmlText, SaoBeiQueryPayRes.class);
        if (posPrePayRe.getReturn_code().equals("01")) {
            switch (posPrePayRe.getTrade_state()) {
                case "SUCCESS":
                    baseResult.setTradeState("SUCCESS");
                    baseResult.setTradeType(dealPayType(posPrePayRe.getPay_type()));
                    baseResult.setTimeEnd(posPrePayRe.getEnd_time());
                    baseResult.setTotalFee(Integer.valueOf(posPrePayRe.getTotal_fee()));
                    baseResult.setOutTradeNo(posPrePayRe.getPay_trace());
                    break;
                case "PAYERROR":
                    baseResult.setTradeState("PAYERROR");
                    break;
                case "NOTPAY":
                    baseResult.setTradeState("REVERSE");
                    break;
                case "CLOSED":
                    baseResult.setTradeState("CLOSED");
                    break;
            }
        }
        return baseResult;
    }

    private JSONObject saoBeiSort(SaoBeiQueryPayReq request, String sign) {
        JSONObject jsonParam = new JSONObject();
        jsonParam.put("pay_ver", request.getPay_ver());
        jsonParam.put("pay_type", request.getPay_type());
        jsonParam.put("service_id", request.getService_id());
        jsonParam.put("merchant_no", request.getMerchant_no());
        jsonParam.put("terminal_id", request.getTerminal_id());
        jsonParam.put("terminal_trace", request.getTerminal_trace());
        jsonParam.put("terminal_time", request.getTerminal_time());
        jsonParam.put("pay_trace", request.getPay_trace());
        jsonParam.put("pay_time", request.getPay_time());
        jsonParam.put("out_trade_no", request.getOut_trade_no());
        jsonParam.put("key_sign", sign);
        return jsonParam;

    }

    public SwiftPassRefundResult saoBeiRefund(Order order, StorePay storePay) throws Exception {
        String prePay_url = base_url + "/pay/100/refund";
        SwiftPassRefundResult refundResult = new SwiftPassRefundResult();
        SaoBeiRefundPayRes payRes;
        SaoBeiRefundPayReq req = new SaoBeiRefundPayReq(order, storePay);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        req.setTerminal_time(simpleDateFormat.format(new Date()));
        req.setPay_time(simpleDateFormat.format(order.getAddTime()));
        String parm = "pay_ver=" + req.getPay_ver() + "&pay_type=" + req.getPay_type() + "&service_id="
                + req.getService_id() + "&merchant_no=" + req.getMerchant_no() + "&terminal_id="
                + req.getTerminal_id() + "&terminal_trace=" + req.getTerminal_trace()
                + "&terminal_time=" + req.getTerminal_time() + "&refund_fee=" + req.getRefund_fee() + "&out_trade_no=" + "" + "&access_token=" + storePay.getAccessToken();
        String sign = sign(parm, "utf-8");
        System.out.println("扫呗退款请求参数" + parm);
        String xmlText = tojson(prePay_url, saoBeiSort(req, sign).toJSONString());
        payRes = JSON.parseObject(xmlText, SaoBeiRefundPayRes.class);
        System.out.println("扫呗退款返回结果" + payRes);
        switch (payRes.getResult_code()) {
            case "01":
                refundResult.setResultCode("0");
                refundResult.setStatus("0");
                refundResult.setRefundId(payRes.getTerminal_trace());
                refundResult.setRefundFee(Integer.valueOf(payRes.getRefund_fee()));
                break;
        }
        return refundResult;
    }

    public AllPayRefundQueryResult saoBeiRefundQuery(StorePay storePay, Order order) throws Exception {
        String prePay_url = base_url + "/pay/100/queryrefund";
        AllPayRefundQueryResult refundResult = new AllPayRefundQueryResult();
        SaoBeiQueryRefundRes payRes;
        SaoBeiRefundPayReq req = new SaoBeiRefundPayReq(order, storePay);
        req.setService_id("031");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        req.setTerminal_time(simpleDateFormat.format(new Date()));
        req.setPay_time(simpleDateFormat.format(order.getAddTime()));
        String parm = "pay_ver=" + req.getPay_ver() + "&pay_type=" + req.getPay_type() + "&service_id="
                + req.getService_id() + "&merchant_no=" + req.getMerchant_no() + "&terminal_id="
                + req.getTerminal_id() + "&terminal_trace=" + req.getTerminal_trace()
                + "&terminal_time=" + req.getTerminal_time() + "&refund_fee=" + req.getRefund_fee() + "&out_trade_no=" + "" + "&access_token=" + storePay.getAccessToken();
        String sign = sign(parm, "utf-8");
        String xmlText = tojson(prePay_url, saoBeiSort(req, sign).toJSONString());
        payRes = JSON.parseObject(xmlText, SaoBeiQueryRefundRes.class);
        if (payRes.getResult_code().equals("01")) {
            if (payRes.getTrade_state().equals("SUCCESS")) {
                refundResult.setStatus("0");
                refundResult.setResultCode("0");
                refundResult.setRefundTime(payRes.getEnd_time());
                refundResult.setRefundId(payRes.getOut_refund_no());
                refundResult.setRefundFee(Integer.valueOf(payRes.getRefund_fee()));
                refundResult.setRefundStatus("SUCCESS");
            } else if (payRes.getTrade_state().equals("REFUNDING")) {
                refundResult.setStatus("0");
                refundResult.setResultCode("0");
                refundResult.setRefundStatus("PROCESSING");
            }
        }
        return refundResult;
    }


    public ALLPayQrCodeResult saoBeiQRCode(StorePay storePay, Order order) throws Exception {
        return (ALLPayQrCodeResult) redisSyncLocker.idLock(order.getId(), new ISyncExecutor() {
            @Override
            public Object execute(Object o) throws Exception {
                String prePay_url = base_url + "/pay/110/qrpay";
                SaoBeiQRCodeReq req = new SaoBeiQRCodeReq(order, storePay);
                ALLPayQrCodeResult result = new ALLPayQrCodeResult();
                req.setNotify_url(baseURL + "/v1/pay/saobei/callBack");
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
                simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
                req.setTerminal_time(simpleDateFormat.format(order.getAddTime()));

                //   Map map = micsort(req);
                //  JSONArray jsonArray = new JSONArray();
                String parm = "merchant_no=" + req.getMerchant_no() + "&notify_url=" + req.getNotify_url() + "&pay_type=" + req.getPay_type() + "&pay_ver="
                        + req.getPay_ver() + "&service_id=" + req.getService_id() + "&terminal_id="
                        + req.getTerminal_id() + "&terminal_time=" + req.getTerminal_time()
                        + "&terminal_trace=" + req.getTerminal_trace() + "&total_fee=" + req.getTotal_fee()
                        + "&access_token=" + storePay.getAccessToken();
                //   jsonArray.add(map);
                // String parm = jsonArray.toString()+"&access_token"+access_token;
                System.out.println("获取签名拼接字符串" + parm);
                String sign = sign(parm, "utf-8");
                String xmlText = tojson(prePay_url, saoBeiSort(req, sign).toJSONString());
                SaoBeiQRCodeRes res = JSON.parseObject(xmlText, SaoBeiQRCodeRes.class);
                if (res.getResult_code().equals("01")) {
                    transactoinTemplate.execute(new TransactionCallbackWithoutResult() {
                        @Override
                        protected void doInTransactionWithoutResult(TransactionStatus status) {
                            order.setPayChannel(OrderPayChannel.SAO_BEI);
                            order.setStatus(OrderStatus.NOTSURE);

                            orderDao.save(order);
                        }
                    });
                    result.setStatus("0");
                    result.setResultCode("0");
                    result.setCodeImgURL(res.getQr_url());
                } else {
                    result.setStatus("1");
                    result.setResultCode("1");
                }
                return result;
            }
        });
    }

    public ALLPayQrCodeResult saobeiRewardQrCode(StorePay storePay, Reward reward) throws Exception {
        return (ALLPayQrCodeResult) redisSyncLocker.idLock(reward.getId(), new ISyncExecutor() {
            @Override
            public Object execute(Object o) throws Exception {
                String prePay_url = base_url + "/pay/110/qrpay";
                SaoBeiQRCodeReq req = new SaoBeiQRCodeReq(reward, storePay);
                ALLPayQrCodeResult result = new ALLPayQrCodeResult();
                req.setNotify_url(baseURL + "/v1/pay/saobei/callBack");
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
                simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
                req.setTerminal_time(simpleDateFormat.format(reward.getAddTime()));


                String parm = "merchant_no=" + req.getMerchant_no() + "&notify_url=" + req.getNotify_url() + "&pay_type=" + req.getPay_type() + "&pay_ver="
                        + req.getPay_ver() + "&service_id=" + req.getService_id() + "&terminal_id="
                        + req.getTerminal_id() + "&terminal_time=" + req.getTerminal_time()
                        + "&terminal_trace=" + req.getTerminal_trace() + "&total_fee=" + req.getTotal_fee()
                        + "&access_token=" + storePay.getAccessToken();

                System.out.println("获取签名拼接字符串" + parm);
                String sign = sign(parm, "utf-8");
                String xmlText = tojson(prePay_url, saoBeiSort(req, sign).toJSONString());
                SaoBeiQRCodeRes res = JSON.parseObject(xmlText, SaoBeiQRCodeRes.class);
                if (res.getResult_code().equals("01")) {
                    transactoinTemplate.execute(new TransactionCallbackWithoutResult() {
                        @Override
                        protected void doInTransactionWithoutResult(TransactionStatus status) {
                            reward.setPayChannel(OrderPayChannel.SAO_BEI);
                            reward.setStatus(OrderStatus.NOTSURE);

                            rewardDao.save(reward);
                        }
                    });
                    result.setStatus("0");
                    result.setResultCode("0");
                    result.setCodeImgURL(res.getQr_url());
                } else {
                    result.setStatus("1");
                    result.setResultCode("1");
                }
                return result;
            }
        });
    }


    public AllPayJsPayResult saoBeiJSPay(StorePay storePay, Order order, String openId) throws Exception {
        return (AllPayJsPayResult) redisSyncLocker.idLock(order.getId(), o -> {
            AllPayJsPayResult result = new AllPayJsPayResult();
            String prePay_url = base_url + "/pay/100/jspay";
            SaoBeiJSPayReq req = new SaoBeiJSPayReq(order, storePay, openId, "wxf6f45bc02f8e7de8");
            req.setNotify_url(baseURL + "/v1/pay/saobei/callBack");
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
            simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
            req.setTerminal_time(simpleDateFormat.format(order.getAddTime()));
            String parm = "pay_ver=" + req.getPay_ver() + "&pay_type=" + req.getPay_type() + "&service_id="
                    + req.getService_id() + "&merchant_no=" + req.getMerchant_no() + "&terminal_id="
                    + req.getTerminal_id() + "&terminal_trace=" + req.getTerminal_trace()
                    + "&terminal_time=" + req.getTerminal_time() + "&total_fee=" + req.getTotal_fee() + "&access_token=" + storePay.getAccessToken();
            String sign = sign(parm, "utf-8");
            String xmlText = tojson(prePay_url, saoBeiSort(req, sign).toJSONString());
            SaoBeiJSPayRes res = JSON.parseObject(xmlText, SaoBeiJSPayRes.class);
            System.out.println("扫呗支付返回结果" + res);
            System.out.println("扫呗支付返回结果" + xmlText);
            if (res.getResult_code().equals("01")) {
                // 更新订单状态到支付中，防止其被更新
                transactoinTemplate.execute(new TransactionCallbackWithoutResult() {
                    @Override
                    protected void doInTransactionWithoutResult(TransactionStatus status) {
                        order.setPayChannel(OrderPayChannel.SAO_BEI);
                        order.setStatus(OrderStatus.NOTSURE);
                        orderDao.save(order);
                    }
                });
                result.setPayInfo(deal(res));
                result.setResultCode("0");
                result.setStatus("0");
            }
            return result;
        });
    }

    public String deal(SaoBeiJSPayRes res) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("appId", res.getAppId());
        jsonObject.put("callback_url", "https://admin.huoxingy.com/static/sucPay/index.html");
        jsonObject.put("nonceStr", res.getNonceStr());
        jsonObject.put("package", res.getPackage_str());
        jsonObject.put("paySign", res.getPaySign());
        jsonObject.put("signType", res.getSignType());
        jsonObject.put("timeStamp", res.getTimeStamp());
        jsonObject.put("status", "0");
        return jsonObject.toJSONString();
    }

    public void saoBeiCallbackForMicroPaymentSuccess(AllPayBaseQueryResult queryResult) throws Exception {
        Order order = orderDao.findOne(queryResult.getOutTradeNo());
        Reward reward = rewardDao.findOne(queryResult.getOutTradeNo());
        if (reward != null) {
            reward.setPayChannel(OrderPayChannel.SAO_BEI);
            if (reward.getStatus().equals(OrderStatus.FINISHED) || reward.getStatus().equals(OrderStatus.UNFINISHED)) {
                // 已经处理过支付成功事件
                return;
            }
            reward.setPaymentTime(MyDateUtils.getDateFormatDd(queryResult.getTimeEnd(), "yyyyMMddHHmmss"));
            reward.setChannel(queryResult.getTradeType());
            reward.setStatus(OrderStatus.FINISHED);
            AccountBalance accountBalance = accountBalanceDao.findByStoreId(reward.getStoreId());
            log.info("accountBalance" + accountBalance);
            if (accountBalance == null) {
                accountBalance = new AccountBalance(queryResult.getTotalFee() / 100.0, reward.getStoreId());
            } else {
                accountBalance.setAmount(accountBalance.getAmount() + queryResult.getTotalFee() / 100.0);
            }
            // 订单与支付信息的更新在同一个事务中
            transactoinTemplate.execute(new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus status) {
                    rewardDao.save(reward);

                }
            });
            accountBalanceDao.save(accountBalance);
            aliyunMNSSend.sendClint(reward.getId());
        } else {
            if (order.getStatus().equals(OrderStatus.FINISHED) || order.getStatus().equals(OrderStatus.UNFINISHED)) {
                // 已经处理过支付成功事件
                return;
            }
            order.setPayChannel(OrderPayChannel.SAO_BEI);
            Store store = storeDao.findOne(order.getStoreId());

            Payment payment = new Payment();
            payment.setId(UuidUtil.getUuid());
            payment.setOrderId(queryResult.getOutTradeNo());
            payment.setStoreId(order.getStoreId());
            payment.setSuccess(queryResult.isSuccess());
            payment.setStatus(PaymentStatus.SUCCESS);
            Date paymentTime = MyDateUtils.getDateFormatDd(queryResult.getTimeEnd(), "yyyyMMddHHmmss");
            payment.setCreateTime(paymentTime);
            payment.setAmount(queryResult.getTotalFee() / 100.0);
            payment.setChannel(queryResult.getTradeType());


            if (OrderSource.POS == order.getSource()) {
                order.setStatus(OrderStatus.FINISHED);
            } else {
                order.setStatus(OrderStatus.UNFINISHED);
            }
            order.setPaymentTime(payment.getCreateTime());
            order.setPayId(payment.getId());
            order.setChannel(queryResult.getTradeType());

            // 订单与支付信息的更新在同一个事务中
            transactoinTemplate.execute(new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus status) {
                    paymentDao.save(payment);
                    orderDao.save(order);
                }
            });

            service.postPaymentSuccess(order, store);
        }
    }


    public void callbackForMicroPaymentFailed(String orderId, AllPayBaseQueryResult queryResult) throws Exception {
        Order order = orderDao.findOne(orderId);
        Reward reward = rewardDao.findOne(orderId);
        if (reward != null) {
            if (reward.getStatus().equals(OrderStatus.INIT)) {
                // 说明已经处理过支付失败的情况
                return;
            } else {
                // 支付失败后订单返回未结算状态，允许再次结算
                reward.setStatus(OrderStatus.INIT);
                transactoinTemplate.execute(new TransactionCallbackWithoutResult() {
                    @Override
                    protected void doInTransactionWithoutResult(TransactionStatus status) {
                        rewardDao.save(reward);
                    }
                });
            }
        } else {
            if (order.getStatus().equals(OrderStatus.CANCELED)) {
                // 说明已经处理过支付失败的情况
                return;
            } else {
                // 支付失败后订单返回未结算状态，允许再次结算
                order.setStatus(OrderStatus.CANCELED);

                transactoinTemplate.execute(new TransactionCallbackWithoutResult() {
                    @Override
                    protected void doInTransactionWithoutResult(TransactionStatus status) {
                        orderDao.save(order);
                    }
                });
            }
        }
    }

    public Map micsort(SaoBeiQRCodeReq request) {
        Map<String, Object> jsonObject = new TreeMap<String, Object>();
        jsonObject.put("pay_ver", request.getPay_ver());
        jsonObject.put("pay_type", request.getPay_type());
        jsonObject.put("service_id", request.getService_id());
        jsonObject.put("merchant_no", request.getMerchant_no());
        jsonObject.put("terminal_id", request.getTerminal_id());
        jsonObject.put("terminal_trace", request.getTerminal_trace());
        jsonObject.put("terminal_time", request.getTerminal_time());
        jsonObject.put("total_fee", request.getTotal_fee());
        return jsonObject;
    }


    public static String tojson(String gateway, String jsonParam) throws Exception {
        String xmlText = "";
        CloseableHttpClient httpclient = HttpClients.custom().build();
        try {

            HttpPost httpPost = new HttpPost(gateway);
            httpPost.addHeader("charset", "UTF-8");
            System.out.println(jsonParam.toString());
            StringEntity stentity = new StringEntity(jsonParam.toString(), "utf-8");//解决中文乱码问题
            stentity.setContentEncoding("UTF-8");
            stentity.setContentType("application/json");
            httpPost.setEntity(stentity);
            CloseableHttpResponse response = httpclient.execute(httpPost);
            try {

                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
                    String text;
                    while ((text = bufferedReader.readLine()) != null) {
                        xmlText = xmlText + text;
                    }
                }

                EntityUtils.consume(entity);
                System.out.println(xmlText);
            } finally {

                response.close();
            }
        } finally {

            httpclient.close();
        }

        return xmlText;
    }


    public JSONObject saoBeiSort(SaoBeiPayReq request, String sign) {
        JSONObject jsonParam = new JSONObject();
        jsonParam.put("pay_ver", request.getPay_ver());
        jsonParam.put("pay_type", request.getPay_type());
        jsonParam.put("service_id", request.getService_id());
        jsonParam.put("merchant_no", request.getMerchant_no());
        jsonParam.put("terminal_id", request.getTerminal_id());
        jsonParam.put("terminal_trace", request.getTerminal_trace());
        jsonParam.put("terminal_time", request.getTerminal_time());
        jsonParam.put("total_fee", request.getTotal_fee());
        jsonParam.put("key_sign", sign);
        jsonParam.put("auth_no", request.getAuth_no());
        return jsonParam;
    }

    public JSONObject saoBeiSort(SaoBeiJSPayReq request, String sign) {
        JSONObject jsonParam = new JSONObject();
        jsonParam.put("pay_ver", request.getPay_ver());
        jsonParam.put("pay_type", request.getPay_type());
        jsonParam.put("service_id", request.getService_id());
        jsonParam.put("merchant_no", request.getMerchant_no());
        jsonParam.put("terminal_id", request.getTerminal_id());
        jsonParam.put("terminal_trace", request.getTerminal_trace());
        jsonParam.put("terminal_time", request.getTerminal_time());
        jsonParam.put("total_fee", request.getTotal_fee());
        jsonParam.put("sub_appid", request.getSub_appid());
        jsonParam.put("open_id", request.getOpen_id());
        jsonParam.put("notify_url", request.getNotify_url());
        jsonParam.put("key_sign", sign);
        return jsonParam;
    }


    public JSONObject saoBeiSort(SaoBeiQRCodeReq request, String sign) {
        JSONObject jsonParam = new JSONObject();
        jsonParam.put("pay_ver", request.getPay_ver());
        jsonParam.put("pay_type", request.getPay_type());
        jsonParam.put("service_id", request.getService_id());
        jsonParam.put("merchant_no", request.getMerchant_no());
        jsonParam.put("terminal_id", request.getTerminal_id());
        jsonParam.put("terminal_trace", request.getTerminal_trace());
        jsonParam.put("terminal_time", request.getTerminal_time());
        jsonParam.put("total_fee", request.getTotal_fee());
        jsonParam.put("notify_url", request.getNotify_url());
        jsonParam.put("key_sign", sign);
        return jsonParam;
    }


    public JSONObject saoBeiSort(SaoBeiRefundPayReq request, String sign) {
        JSONObject jsonParam = new JSONObject();
        jsonParam.put("pay_ver", request.getPay_ver());
        jsonParam.put("pay_type", request.getPay_type());
        jsonParam.put("service_id", request.getService_id());
        jsonParam.put("merchant_no", request.getMerchant_no());
        jsonParam.put("terminal_id", request.getTerminal_id());
        jsonParam.put("terminal_trace", request.getTerminal_trace());
        jsonParam.put("terminal_time", request.getTerminal_time());
        jsonParam.put("refund_fee", request.getRefund_fee());
        jsonParam.put("out_trade_no", request.getOut_trade_no());
        jsonParam.put("pay_trace", request.getPay_trace());
        jsonParam.put("pay_time", request.getPay_time());
        jsonParam.put("key_sign", sign);
        return jsonParam;
    }


    public static String sign(String text, String input_charset) {
        return DigestUtils.md5Hex(getContentBytes(text, input_charset));
    }

    /**
     * @param content
     * @param charset
     * @return
     * @throws
     * @throws
     */
    private static byte[] getContentBytes(String content, String charset) {
        if (charset == null || "".equals(charset)) {
            return content.getBytes();
        }
        try {
            return content.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
        }
    }

    private String dealPayType(String type) {
        String payType = "";
        switch (type) {
            case "010":
                payType = "pay.wechat.native";
                break;
            case "020":
                payType = "pay.alipay.native";
                break;
            case "060":
                payType = "pay.qq.micropay";
                break;
            case "080":
                payType = "pay.jdpay.micropay";
                break;
            case "100":
                payType = "pay.bestpay.micropay";
                break;
            case "110":
                payType = "pay.unionpay.micropay";
                break;
        }
        return payType;

    }

    public void callbackForThirdPartyRefundFail(AllPayRefundQueryResult result) {
        Order refundOrder = orderDao.findOne(result.getOutRefundNo());
        refundOrder.setStatus(OrderStatus.INIT);
        refundOrder.setPayChannel(OrderPayChannel.SAO_BEI);
        transactoinTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                orderDao.save(refundOrder);
            }
        });
    }

    public void callbackForThirdPartyRefundSuccess(AllPayRefundQueryResult result) {
        log.debug("Step in callback for third party refund success...");
        Payment payment = paymentDao.findOne(result.getRefundId());
        payment.setStatus(PaymentStatus.SUCCESS);
        payment.setSuccess(true);

        Date paymentTime = MyDateUtils.getDateFormatDd(result.getRefundTime(), "yyyyMMddHHmmss");
        payment.setCreateTime(paymentTime);

        Order refundOrder = orderDao.findOne(payment.getOrderId());
        refundOrder.setPayChannel(OrderPayChannel.SAO_BEI);
        refundOrder.setStatus(OrderStatus.REFUNDED);
        refundOrder.setPaymentTime(paymentTime);

        transactoinTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                orderDao.save(refundOrder);
                paymentDao.save(payment);
            }
        });

        try {
            service.postRefundSuccess(refundOrder);
        } catch (Exception e1) {
            log.info(e1.toString());
        }
    }

}
